package com.mine.mybatis.session.defaults;

import com.mine.mybatis.excutor.Executor;
import com.mine.mybatis.excutor.SimpleExecutor;
import com.mine.mybatis.mapping.MappedStatement;
import com.mine.mybatis.session.Configuration;
import com.mine.mybatis.session.SqlSession;

import java.lang.reflect.*;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.List;

public class DefaultSqlSession implements SqlSession {

    private Configuration configuration;

    private Executor executor;

    public DefaultSqlSession(Configuration configuration) {
        this.configuration = configuration;
        // 使用默认的执行器
        this.executor = new SimpleExecutor();
    }

    @Override
    public <T> T selectOne(String statementId, Object param) throws Exception {

        List list = selectList(statementId,param);
        if(list.size() == 1){
            return (T) list.get(0);
        }else{
            throw  new RuntimeException("查询的结果集为空或者多个");
        }

    }

    @Override
    public <E> List<E> selectList(String statementId, Object param) throws Exception {
        // 将要去完成对SimpleExecutor里的query方法的调用
        MappedStatement ms = this.configuration.getMappedStatement(statementId);

        // 这是我们指定一个默认的执行器去执行
        List<E> list = this.executor.query(this.configuration,ms,param);

        return list;
    }

    @Override
    public int insert(String statementId, Object param) throws Exception {
        return this.update(statementId,param);
    }

    @Override
    public int update(String statementId, Object param) throws Exception {

        MappedStatement ms = this.configuration.getMappedStatement(statementId);
        return this.executor.update(this.configuration,ms,param);
    }

    @Override
    public int delete(String statementId, Object param) throws Exception {
        return this.update(statementId,param);
    }

    @Override
    public <T> T getMapper(Class<T> mapperClass) {
        // 使用JDK动态代理来为Dao层接口生成代理对象，并返回。
        Object proxyInstance = Proxy.newProxyInstance(mapperClass.getClassLoader(), new Class[]{mapperClass}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                /**
                 * 底层都还是去执行JDBC代码
                 * 根据不同情况来调用findAll或者findByCondition方法
                 * 准备参数：
                 * 1.statementId: sql语句的唯一标识 nnamespace.id = 接口全限定名.方法名
                 */
                // 方法名
                String methodNme = method.getName();
                String className = method.getDeclaringClass().getName();

                String   statementId  = className + "." + methodNme;

                // 准备参数 2.params:args
                // 获取被调用方法的返回值类型
                Type genericReturnType = method.getGenericReturnType();

                if (methodNme.contains("insert")||methodNme.contains("update")||methodNme.contains("delete")) {
                    return update(statementId, args[0]);
                }

                // 判断是否进行了泛型类型参数化
                if (genericReturnType instanceof ParameterizedType) {
                    List<Object> objects = selectList(statementId, args[0]);
                    return objects;
                }
                return selectOne(statementId, args[0]);
            }
        });
        return (T) proxyInstance;
    }
}
